/** Copy from Twitter, Inc. And modify it. */
package b.utils.entity

import akka.event.slf4j.SLF4JLogging

import scala.util.matching.Regex

/**
 * An object that generates IDs.
 * This is broken into a separate class in case
 * we ever want to support multiple worker threads
 * per process
 */
class C流水号产生器(v机器号: Int, v集群号: Int, var sequence: Long = 0L) extends SLF4JLogging {

  val theEpoch = 1158234574157L // 纪元，时间戳基数

  private[this] val workerIdBits = 5L
  private[this] val dataCenterIdBits = 5L
  private[this] val maxWorkerId = -1L ^ (-1L << workerIdBits)
  private[this] val maxDataCenterId = -1L ^ (-1L << dataCenterIdBits)
  private[this] val sequenceBits = 12L

  private[this] val workerIdShift = sequenceBits
  private[this] val dataCenterIdShift = sequenceBits + workerIdBits
  private[this] val timestampLeftShift = sequenceBits + workerIdBits + dataCenterIdBits
  private[this] val sequenceMask = -1L ^ (-1L << sequenceBits)

  private[this] var lastTimestamp = -1L

  // sanity check for workerId
  require(v机器号 <= maxWorkerId && v机器号 >= 0,
    "worker-id can't be greater than %d or less than 0".format(maxWorkerId))

  require(v集群号 <= maxDataCenterId && v集群号 >= 0,
    "data-center Id can't be greater than %d or less than 0".format(maxDataCenterId))

  log.info("worker starting. timestamp left shift %d, data-center id bits %d, worker id bits %d, sequence bits %d, worker-id %d".format(
    timestampLeftShift, dataCenterIdBits, workerIdBits, sequenceBits, v机器号))

  def nextId(): Long = synchronized {
    var timestamp = timeGenerate()

    if (timestamp < lastTimestamp) {
      log.error("clock is moving backwards. Rejecting requests until %d.", lastTimestamp)
      require(requirement = false,
        "Clock moved backwards. Refusing to generate id for %d milliseconds".format(lastTimestamp - timestamp))
    }

    if (lastTimestamp == timestamp) {
      sequence = (sequence + 1L) & sequenceMask
      if (sequence == 0L)
        timestamp = tilNextMillis(lastTimestamp)
    } else
      sequence = 0L

    lastTimestamp = timestamp
    ((timestamp - theEpoch) << timestampLeftShift) |
      (v集群号 << dataCenterIdShift) |
      (v机器号 << workerIdShift) |
      sequence
  }

  private[this] def tilNextMillis(lastTimestamp: Long): Long = {
    var timestamp = timeGenerate()
    while (timestamp <= lastTimestamp)
      timestamp = timeGenerate()
    timestamp
  }

  private[this] def timeGenerate(): Long = System.currentTimeMillis()

}
